﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace DroughtAnalysis
{
    /// <summary>
    /// Modifies the R-script by setting the output directory, input file path and station name 
    /// parameters.
    /// </summary>
    public static class RScriptModifier
    {
        /// <summary>
        /// Creates a large "combined" R-script with a loop for all stations
        /// </summary>
        /// <param name="inputScriptPath">the input script path</param>
        /// <param name="outputScriptPath">the output script path</param>
        /// <param name="droughtStations">the list of drought stations for which drought should be calculated</param>
        public static void CreateCombinedRScript(string inputScriptPath, string outputScriptPath, IList<DroughtSiteInfo> droughtStations, DroughtMethodInfo droughtMethod)
        {
            ScriptTemplateReader templateReader = new ScriptTemplateReader();
            string template = templateReader.GetScriptTemplate(inputScriptPath);

            //generate script loop header
            StringBuilder fileNamesVector = new StringBuilder("soubory = c(");
            StringBuilder stationNamesVector = new StringBuilder("nazvystanic = c(");
            StringBuilder directoriesVector = new StringBuilder("adresare = c(");

            foreach(DroughtSiteInfo station in droughtStations)
            {
                string outputDirectory = station.ResultDirectory;
                
                //string inputFilePath = Path.Combine(station.ResultDirectory,
                //    string.Format("{0}_data.dat", StationNameHelper.GetStationFileName(station.Site.Name)));

                string inputFilePath2 = Path.Combine(station.ResultDirectory, droughtMethod.InputFiles[0]); //using the file from 'inputFiles'

                string stationName = StationNameHelper.GetStationFileName(station.Site.Name);

                fileNamesVector.Append("'" + inputFilePath2.Replace(@"\", "/") + "'");
                stationNamesVector.Append("'" + stationName + "'");
                directoriesVector.Append("'" + outputDirectory.Replace(@"\", "/") + "'");
                if (droughtStations.IndexOf(station) == droughtStations.Count - 1)
                {
                    fileNamesVector.Append(")");
                    stationNamesVector.Append(")");
                    directoriesVector.Append(")");
                }
                else
                {
                    fileNamesVector.Append(",");
                    stationNamesVector.Append(",");
                    directoriesVector.Append(",");                   
                }
            }

            using (StringReader reader = new StringReader(template))
            {
                using (StreamWriter writer = new StreamWriter(outputScriptPath, false))
                {
                    //add settings for error message display
                    //writer.WriteLine("options(show.error.messages = FALSE)");
                    //writer.WriteLine("options(warn = FALSE)");
                    
                    //add the header lines
                    writer.WriteLine(fileNamesVector.ToString());
                    writer.WriteLine(stationNamesVector.ToString());
                    writer.WriteLine(directoriesVector.ToString());

                    //add start of function
                    writer.WriteLine(@"executescript <- function(adresare, soubory, station_id){");

                    //add the FOR loop
                    //writer.WriteLine("for(station_id in 1:length(soubory)) {");

                    //add a line which sets the proper working directory
                    writer.WriteLine("setwd(adresare[station_id])");

                    bool stationNameParamReplaced = false;
                    bool inputFileParamReplaced = false;
                    
                    string line = String.Empty;
                    while ((line = reader.ReadLine()) != null)
                    {
                        //replace line with nazev stanice
                        if (!stationNameParamReplaced)
                        {
                            if (line.Contains("Nazevstanice ="))
                            {
                                line = @"Nazevstanice = nazvystanic[station_id]; print(paste(Nazevstanice, "": "", station_id, ""/"", length(soubory)))";
                                stationNameParamReplaced = false;
                            }
                        }
                        //replace line with soubor (this is the input file path
                        if (!inputFileParamReplaced)
                        {
                            if (line.Contains("soubor ="))
                            {
                                line = "soubor = soubory[station_id]";
                            }
                        }

                        writer.WriteLine(line);
                    }

                    //write end of for loop
                    writer.WriteLine("}");

                    //write the function and error catching
                    writer.WriteLine("for(station_id in 1:length(soubory)) {");
                    writer.WriteLine("  possibleError <- tryCatch(");
                    writer.WriteLine("  executescript(adresare, soubory, station_id),");
                    writer.WriteLine("  error=function(e) e");
                    writer.WriteLine("  )");
                    writer.WriteLine("  if (!inherits(possibleError, 'error')){");
                    writer.WriteLine("    executescript(adresare, soubory, station_id)");
                    writer.WriteLine("  }");
                    writer.WriteLine("}");

                    //writer.WriteLine("print 'Calculation Complete!'");
                }
            }
        }
                  
        /// <summary>
        /// Modifies the R-script and saves it to the output path
        /// </summary>
        /// <param name="inputScriptName">The input script template name</param>
        /// <param name="outputScriptPath">The output script path</param>
        /// <param name="parameters">The parameters to be modified</param>
        public static void ModifyRScript(string inputScriptName, string outputScriptPath, RScriptParameterInfo parameters)
        {
            ScriptTemplateReader templateReader = new ScriptTemplateReader();
            string template = templateReader.GetScriptTemplate(inputScriptName);

            if (template == string.Empty)
            {
                //if (!File.Exists(inputScriptPath))
                throw new FileNotFoundException("The R script '" + inputScriptName + "' doesn't exist!");
            }
            //check the parameters passed in
            //param 1 working directory
            if (!Directory.Exists(parameters.OutputDirectory))
                throw new DirectoryNotFoundException(string.Format("The Directory '{0}' doesn't exist!"));
            //param 2 the input file
            if (!File.Exists(parameters.InputFilePath))
                throw new FileNotFoundException(string.Format("The input file '{0}' doesn't exist!"));
            //param 3 the station name
            if (String.IsNullOrWhiteSpace(parameters.StationName))
                throw new ArgumentException("The station name is not specified!");

            string line = string.Empty;
            bool inputFileParamReplaced = false; //this stays false until all required
            bool stationNameParamReplaced = false; //this stays false until the station name param is replaced.

                                                //parameters are replaced.
            using (StringReader reader = new StringReader(template))
            {
                using (StreamWriter writer = new StreamWriter(outputScriptPath, false))
                {
                    //add settings for error message display
                    //writer.WriteLine("options(show.error.messages = FALSE)");
                    //writer.WriteLine("options(warn = FALSE)");
                    
                    //add a line which sets the proper working directory
                    string workDir = parameters.OutputDirectory.Replace(@"\", "/");
                    writer.WriteLine("setwd('" + workDir + "')");
                    
                    
                    while ((line = reader.ReadLine()) != null)
                    {
                        //replace line with nazev stanice
                        if (!stationNameParamReplaced)
                        {
                            if (line.Contains("Nazevstanice ="))
                            {
                                line = string.Format("Nazevstanice = '{0}'", parameters.StationName);
                                stationNameParamReplaced = false;
                            }
                        }
                        //replace line with soubor (this is the input file path
                        if (!inputFileParamReplaced)
                        {
                            if (line.Contains("soubor ="))
                            {
                                string inputFile = parameters.InputFilePath.Replace(@"\","/");
                                line = string.Format("soubor = '{0}'", inputFile);
                            }
                        }

                        writer.WriteLine(line);
                    }
                }
            }
        }
        
    }
    /// <summary>
    /// Parameters of the R script
    /// </summary>
    public class RScriptParameterInfo
    {
        /// <summary>
        /// Gets or sets the output directory
        /// </summary>
        public string OutputDirectory { get; set; }
        /// <summary>
        /// Gets or sets the input file name
        /// </summary>
        public string InputFilePath { get; set; }
        /// <summary>
        /// Gets or sets the station name
        /// </summary>
        public string StationName { get; set; }
    }
}
